﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using ScrumTable.Common;
using ScrumTable.Common.Collections;
using ScrumTable.Common.EventHandling;
using ScrumTable.Common.Threading;
using ScrumTable.DL.Data.Common;
using ScrumTable.DL.Data.Generic.Cache;

#endregion


namespace ScrumTable.DL.Data.Generic
{
    /// <summary>
    /// This class encapsulates the base data access object service
    /// routines in order to access data from an external system. This
    /// implementation contains additional functionalities for workitem
    /// handling.
    /// </summary>
    /// <remarks>The implementation of the data object class follows the Data Access Object pattern.</remarks>
    internal abstract class WorkItemDataAccessObjectBase : DataAccessObjectBase
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the associated work item type to the current data access
        /// object.
        /// </summary>
        protected abstract CacheWorkItemType WorkItemType { get; }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new WorkItemDataAccessObjectBase instance, no public constructor
        /// needed.
        /// </summary>
        internal WorkItemDataAccessObjectBase(GenericDataContextBase context)
            : base(context)
        {
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Releases managed (c# or .net) resources.
        /// </summary>
        protected override void ReleaseManagedResources()
        {
            OnDisconnected();
        }

        /// <summary>
        /// Creates a new WorkItem based data object instance.
        /// </summary>
        /// <param name="element">Specifies the work item element to create.</param>
        /// <returns>Returns the created data object wrapper around the given workitem.</returns>
        protected abstract IDataObject CreateWorkItemDataObject(CacheWorkItem element);

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        /// <summary>
        /// Retrieves a call after the initial data of the back-end system has
        /// been loaded.
        /// </summary>
        internal override void OnInitialized()
        {
            Context.DataCache.CurrentProject.WorkItems.WorkItemChange += OnWorkItemChange;
        }

        /// <summary>
        /// Retrieves a call after the connection to the back-end system has
        /// been closed.
        /// </summary>
        internal override void OnDisconnected()
        {
            if (Context.DataCache != null
                && Context.DataCache.CurrentProject != null
                && Context.DataCache.CurrentProject.WorkItems != null)
            {
                Context.DataCache.CurrentProject.WorkItems.WorkItemChange -= OnWorkItemChange;
            }
        }

        private void OnWorkItemChange(object sender, CacheElementListChangedEventArgs<CacheWorkItem> e)
        {
            // only fire events which have been addressed
            // to the current object (and its managed types)
            if (e.Bucket.Element.Type != WorkItemType)
                return;

            switch (e.ChangeAction)
            {
                case CacheElementListChangeAction.None:
                    break;
                case CacheElementListChangeAction.Add:
                    OnDataAccessObjectChanged(
                        new DataAccessObjectChangedEventArgs(
                            DataAccessObjectChangedAction.Add,
                            e.ParentChain,
                            CreateWorkItemDataObject(e.Bucket.Element)));
                    break;
                case CacheElementListChangeAction.Remove:
                    OnDataAccessObjectChanged(
                        new DataAccessObjectChangedEventArgs(
                            DataAccessObjectChangedAction.Remove,
                            e.ParentChain,
                            e.Bucket.Element.UniqueId));
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        #endregion
    }
}